`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/09/11 13:47:35
// Design Name: 
// Module Name: MRT_wrapper
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module MRT_wrapper#(
     parameter DATA_IN_WIDTH      = 24     ,
	 parameter DATA_OUT_WIDTH     = 32     ,
	 parameter DP = 8192,
      parameter FORCE_X2ZERO = 0,
      parameter MW = 3,
      parameter AW = 13 
    )(
   input                        i_clk                    ,
   input                        i_rstn                   ,
   input                        i_ena                    ,
   input                          i_wen                  ,
   input                          work_mode              ,
   input    [2*DATA_IN_WIDTH-1: 0]  i_cfg_data           , // q,i
   input                           i_cfg_last           ,
   output   [DATA_OUT_WIDTH-1:0]  u42a_data              , //27bit fra 
   output                         u42a_data_valid        ,
   output   [DATA_OUT_WIDTH-1:0]  sigma_dp_data          , //23bit fra
   output                         sigma_dp_data_valid    ,
   output  signed [DATA_OUT_WIDTH-1:0]    psy_data                 , //   27bitfra       
   output                                 psy_data_valid           ,
   output   [DATA_OUT_WIDTH-1:0]          gama_m_data              , //20bit fra
   output                                 gama_m_data_valid        
    );
    
    wire [DATA_IN_WIDTH-1:0] input_data_i0, input_data_q0;
    wire [DATA_IN_WIDTH-1:0] input_data_i1, input_data_q1;
    wire [2*DATA_IN_WIDTH-1:0] input_data;
    reg input_data_vld;
    reg input_data_last;
    reg [AW-1:0] addr;
    wire [AW-1:0] ram0_addr, ram1_addr;
    
    wire ram0_wen;
    wire ram1_wen;
    reg [AW-1+1:0] waddr;
    
    
    assign ram0_wen = i_wen & ~waddr[AW];
    assign ram1_wen = i_wen & waddr[AW];
    assign ram0_addr = ram0_wen  ? waddr[AW-1:0] : addr;
    assign ram1_addr = ram1_wen  ? waddr[AW-1:0] : addr;
    assign input_data = waddr[AW]?{input_data_q0, input_data_i0}:{input_data_q1, input_data_i1};
        
    mrt_i_ram u_mrt_i_ram0(
    .clk(i_clk), 
    .din(i_cfg_data[DATA_IN_WIDTH-1:0]), 
    .addr(ram0_addr),
    .cs(1'b1),
    .we(ram0_wen),
    .wem({MW{1'b1}}),
    .dout(input_data_i0)
    );
    
    mrt_q_ram u_mrt_q_ram0(
    .clk(i_clk), 
    .din(i_cfg_data[2*DATA_IN_WIDTH-1:DATA_IN_WIDTH]), 
    .addr(ram0_addr),
    .cs(1'b1),
    .we(ram0_wen),
    .wem({MW{1'b1}}),
    .dout(input_data_q0)
    );
    
    mrt_i_ram u_mrt_i_ram1(
    .clk(i_clk), 
    .din(i_cfg_data[DATA_IN_WIDTH-1:0]), 
    .addr(ram1_addr),
    .cs(1'b1),
    .we(ram1_wen),
    .wem({MW{1'b1}}),
    .dout(input_data_i1)
    );
    
    mrt_q_ram u_mrt_q_ram1(
    .clk(i_clk), 
    .din(i_cfg_data[2*DATA_IN_WIDTH-1:DATA_IN_WIDTH]), 
    .addr(ram1_addr),
    .cs(1'b1),
    .we(ram1_wen),
    .wem({MW{1'b1}}),
    .dout(input_data_q1)
    );
    
    wire mrt_core_rstn;
    reg mrt_normal_rstn;
    assign mrt_core_rstn = i_rstn & mrt_normal_rstn;
    
    Modulation_Recognition_top mrt_core(
   .i_clk                    (i_clk) ,
   .i_rstn                   (mrt_core_rstn) ,
   .work_mode                (work_mode),
 
   .i_Data_In_Valid          (input_data_vld) ,
   .i_Data_In                (input_data),
   .i_Data_In_Last           (input_data_last),


   .u42a_data                (u42a_data) ,
   .u42a_data_valid          (u42a_data_valid) ,
   .sigma_dp_data            (sigma_dp_data),
   .sigma_dp_data_valid      (sigma_dp_data_valid),
   .gama_m_data              (gama_m_data),
   .gama_m_data_valid        (gama_m_data_valid),
   .psy_data                 (psy_data),
   .psy_data_valid           (psy_data_valid)
    );
    wire data_miss;
    always @(posedge i_clk)begin
        if(~i_rstn) waddr <= 14'd0;
        else waddr <= data_miss ? {waddr[AW] ,13'd0} 
                    : i_wen      ? waddr+1 : waddr
                    ;
    end
    
    
    reg data_ready;
    wire data_ready_ena;

    assign data_miss = i_wen & (waddr[AW-1:0]<13'd8191) & i_cfg_last;
    assign data_ready_ena = i_wen & (waddr[AW-1:0]==13'd8191) & i_cfg_last;
    
    
    
    always @(posedge i_clk) 
	begin
		if(!i_rstn)
			begin
				data_ready <= 0	;

			end
		else 
			begin
				data_ready <= data_ready_ena	   ;

			end
	end
    
//    sirv_gnrl_dfflr #(1)   data_ready_dfflr (1'b1, data_ready_ena, data_ready, i_clk, i_rstn);
    /////*************************************Control*******************************////      
                    reg [1:0] state,next_state;
                    reg [32-1:0]  rd_count;
                    wire halt_end;
                    wire output2_end;
//                   reg flag;
                  
                   localparam Init=2'b00, output1=2'b01, halt= 2'b10, output2=2'b11;
                    always @(*) begin
                        case(state)
                            Init: begin
                                if(~i_rstn | ~i_ena | ~data_ready) next_state = Init;
                                else next_state = output1;
                            end
                            output1: begin
                                if(~i_rstn) next_state = Init;
                               else if(input_data_last) next_state = halt;
                                               else next_state = output1;
                            end
                            halt: begin 
                                if(~i_rstn) next_state = Init;
                               else if(halt_end) next_state = output2;
                                               else next_state = halt;
                            end
                            output2: begin
                                if(~i_rstn) next_state = Init;
                                else if(output2_end) next_state = Init;
                                else next_state = output2;
                            end  
                        endcase
                    end
                    
                    // State transfer block
                    always @(posedge i_clk) begin
                        if(~i_rstn) state <= Init;
                        else state <= next_state;
                    end
                    
                
                    // State output
                    always @(posedge i_clk) begin
                        // in default we disable and reset all counter
                        input_data_vld      <= 0;
                        input_data_last     <= 0; // output data is invalid
                        rd_count            <= 0;
                        addr                <= 0;
                        mrt_normal_rstn      <= work_mode?~gama_m_data_valid:~u42a_data_valid;
                        case(next_state)
                            Init: ; // do as the default
                            output1: begin
                                input_data_vld <= 1;
                                input_data_last <= (rd_count == DP-1);
                                rd_count     <= rd_count + 1;
                                addr         <= (addr==DP-1) ? 0 : addr + 1;
                                end
                            halt: begin
                                input_data_vld <= 1'b0;
                                input_data_last <= 1'b0;
                                rd_count     <= rd_count + 1;
                                addr         <= 0;
                                end
                            output2: begin
                                input_data_vld <= 1;
                                input_data_last <= 1'b0;
                                rd_count     <= rd_count + 1;
                                addr         <= (addr==DP-1) ? 0 : addr + 1;
                           end
                           default: ;
                        endcase
                    end
            assign halt_end = (rd_count==DP+1);
            assign output2_end = (rd_count == DP*2+1);
    
    
endmodule

module mrt_i_ram 
#(parameter DP = 8192,
  parameter FORCE_X2ZERO = 0,
  parameter DW = 24,
  parameter MW = 3,
  parameter AW = 13 
)
(
  input             clk, 
  input  [DW-1  :0] din, 
  input  [AW-1  :0] addr,
  input             cs,
  input             we,
  input  [MW-1:0]   wem,
  output [DW-1:0]   dout
);

    reg [DW-1:0] mem_r [0:DP-1];
    
    integer ii;
    initial begin $readmemh("D:/project_recent/mr_matlab_0917/txtforvivado/FM20dbI.txt", mem_r); end
    
    reg [AW-1:0] addr_r;
    wire [MW-1:0] wen;
    wire ren;

    assign ren = cs & (~we);
    assign wen = ({MW{cs & we}} & wem);





    always @(posedge clk)
    begin
        if (ren) begin
            addr_r <= addr;
        end
    end
    genvar i;
    generate
      for (i = 0; i < MW; i = i+1) begin :mem
        if((8*i+8) > DW ) begin: last
          always @(posedge clk) begin
            if (wen[i]) begin
               mem_r[addr][DW-1:8*i] <= din[DW-1:8*i];
            end
          end
        end
        else begin: non_last
          always @(posedge clk) begin
            if (wen[i]) begin
               mem_r[addr][8*i+7:8*i] <= din[8*i+7:8*i];
            end
          end
        end
      end
    endgenerate

  wire [DW-1:0] dout_pre;
  assign dout_pre = mem_r[addr_r];

  generate
   if(FORCE_X2ZERO == 1) begin: force_x_to_zero
      for (i = 0; i < DW; i = i+1) begin:force_x_gen 
          `ifndef SYNTHESIS//{
         assign dout[i] = (dout_pre[i] === 1'bx) ? 1'b0 : dout_pre[i];
          `else//}{
         assign dout[i] = dout_pre[i];
          `endif//}
      end
   end
   else begin:no_force_x_to_zero
     assign dout = dout_pre;
   end
  endgenerate

 
endmodule

module mrt_q_ram 
#(parameter DP = 8192,
  parameter FORCE_X2ZERO = 0,
  parameter DW = 24,
  parameter MW = 3,
  parameter AW = 13 
)
(
  input             clk, 
  input  [DW-1  :0] din, 
  input  [AW-1  :0] addr,
  input             cs,
  input             we,
  input  [MW-1:0]   wem,
  output [DW-1:0]   dout
);

    reg [DW-1:0] mem_r [0:DP-1];
    
    integer ii;
    initial begin $readmemh("D:/project_recent/mr_matlab_0917/txtforvivado/FM20dbI.txt", mem_r); end
    
    reg [AW-1:0] addr_r;
    wire [MW-1:0] wen;
    wire ren;

    assign ren = cs & (~we);
    assign wen = ({MW{cs & we}} & wem);





    always @(posedge clk)
    begin
        if (ren) begin
            addr_r <= addr;
        end
    end
    genvar i;
    generate
      for (i = 0; i < MW; i = i+1) begin :mem
        if((8*i+8) > DW ) begin: last
          always @(posedge clk) begin
            if (wen[i]) begin
               mem_r[addr][DW-1:8*i] <= din[DW-1:8*i];
            end
          end
        end
        else begin: non_last
          always @(posedge clk) begin
            if (wen[i]) begin
               mem_r[addr][8*i+7:8*i] <= din[8*i+7:8*i];
            end
          end
        end
      end
    endgenerate

  wire [DW-1:0] dout_pre;
  assign dout_pre = mem_r[addr_r];

  generate
   if(FORCE_X2ZERO == 1) begin: force_x_to_zero
      for (i = 0; i < DW; i = i+1) begin:force_x_gen 
          `ifndef SYNTHESIS//{
         assign dout[i] = (dout_pre[i] === 1'bx) ? 1'b0 : dout_pre[i];
          `else//}{
         assign dout[i] = dout_pre[i];
          `endif//}
      end
   end
   else begin:no_force_x_to_zero
     assign dout = dout_pre;
   end
  endgenerate

 
endmodule